/*
*********************************************************************************************************
*	                                  
*	模块名称 : STM32内部看门狗
*	文件名称 : bsp_watchdog.c
*	版    本 : V1.0
*	说    明 : STM32内部独立看门狗IWDG和窗口看门狗WWDG驱动程序
*	修改记录 :
*		版本号   日期        作者     说明
*		V1.0    2015-10-06  armfly   正式发布
*
*	Copyright (C), 2015-2020, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/

#include "bsp.h"

static void bsp_InitIwdg(uint32_t _ulIWDGTime);

/*
*********************************************************************************************************
*	函 数 名: bsp_StartDog
*	功能说明: 启动看门狗， 独立看门狗设置为 1000ms, 窗口看门狗不使能。
*	形    参: 无
*	返 回 值: 无		        
*********************************************************************************************************
*/
void bsp_StartDog(void)
{
	/* 启动独立看门狗, 超时1000ms */
	bsp_InitIwdg(1000);
	
	
	/*
		窗口看门狗初始化
		窗口刷新时间段: ~780 * (0x7f-0x50) = 36.6ms < refresh window < ~780 * 64 = 49.9ms
		
		首先设置计数器值是 0x7f，窗口值是 0x50，我们不能够在计数器递减到 0x50 之前做刷新		
	*/
	//bsp_InitWwdg(0x7f, 0x50, WWDG_Prescaler_8);
}

/*
*********************************************************************************************************
*	函 数 名: bsp_FeedDog
*	功能说明: 喂狗函，针对独立看门狗
*	形    参: 无
*	返 回 值: 无		        
*********************************************************************************************************
*/
void bsp_FeedDog(void)
{
	IWDG_ReloadCounter();
}

/*
*********************************************************************************************************
*	函 数 名: bsp_InitIwdg
*	功能说明: 独立看门狗时间配置函数
*	形    参: IWDGTime: 0 ---- 0x0FFF
*			  独立看门狗时间设置,单位为ms,IWDGTime = 1000 大约就是一秒的时间
*			  LSI = 34000左右
*	返 回 值: 无		        
*********************************************************************************************************
*/
static void bsp_InitIwdg(uint32_t _ulIWDGTime)
{
		
	/* 检测系统是否从独立看门狗复位中恢复 */
	if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
	{		
		/* 清除复位标志 */
		RCC_ClearFlag();
	}
	else
	{
		/* 标志没有设置 */
	}
	
	/* 使能LSI */
	RCC_LSICmd(ENABLE);
	
	/* 等待直到LSI就绪 */
	while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
	{}
	
	/* 写入0x5555表示允许访问IWDG_PR 和IWDG_RLR寄存器 */
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	
	/*  LSI/32 分频， 之后周期差不多1ms */
	IWDG_SetPrescaler(IWDG_Prescaler_32);
	
	/*
		特别注意，由于这里_ulIWDGTime的最小单位是ms, 所以这里重装计数的计数时 需要除以1000
	 	Counter Reload Value = (_ulIWDGTime / 1000) /(1 / IWDG counter clock period)
	                      = (_ulIWDGTime / 1000) / (32/LSI)
	                      = (_ulIWDGTime / 1000) / (32/LsiFreq)
	                      = LsiFreq * _ulIWDGTime / 32000
	 	实际测试LsiFreq = 34000，所以这里取1的时候 大概就是1ms 
	*/
	IWDG_SetReload(_ulIWDGTime);
	
	/* 重载IWDG计数 */
	IWDG_ReloadCounter();
	
	/* 使能 IWDG (LSI oscillator 由硬件使能) */
	IWDG_Enable();		
}

/*
*********************************************************************************************************
*	函 数 名: bsp_InitWwdg
*	功能说明: 窗口看门狗配置 
*	形    参：
*             _ucTreg       : T[6:0],计数器值 	范围0x40 到 0x7F                                               
*             _ucWreg       : W[6:0],窗口值     必须小于 0x80
*            WWDG_Prescaler : 窗口看门狗分频	PCLK1 = 42MHz
*                             WWDG_Prescaler_1: WWDG counter clock = (PCLK1/4096)/1
*							  WWDG_Prescaler_2: WWDG counter clock = (PCLK1/4096)/2
*							  WWDG_Prescaler_4: WWDG counter clock = (PCLK1/4096)/4
*							  WWDG_Prescaler_8: WWDG counter clock = (PCLK1/4096)/8 
*	返 回 值: 无		        
*********************************************************************************************************
*/
void bsp_InitWwdg(uint8_t _ucTreg, uint8_t _ucWreg, uint32_t WWDG_Prescaler)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	/* 检测系统是否从窗口看门狗复位中恢复 */
	if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET)
	{ 	
		/* 清除复位标志 */
		RCC_ClearFlag();
	}
	else
	{
		/* WWDGRST 标志没有设置 */
	}
	
	/* 使能WWDG时钟 */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
	
	/* 
	   窗口看门狗分频设置：
	   比如选择WWDG_Prescaler_8
	   (PCLK1 (42MHz)/4096)/8 = 1281 Hz (~780 us)  
	*/
	WWDG_SetPrescaler(WWDG_Prescaler);
	
	/* 
	 设置窗口值是_ucWreg，用户必须在小于_ucWreg且大于0x40时刷新计数
	 器，要不会造成系统复位。
    */
	WWDG_SetWindowValue(_ucWreg);
	
	/* 
	 使能WWDG，设置计数器
	 比如设置_ucTreg=127 8分频时，那么溢出时间就是= ~780 us * 64 = 49.92 ms 
	 窗口看门狗的刷新时间段是: ~780 * (127-80) = 36.6ms < 刷新窗口看门狗 < ~780 * 64 = 49.9ms
	*/
	WWDG_Enable(_ucTreg);
	
	/* 清除EWI中断标志 */
	WWDG_ClearFlag();	

	/* 使能EW中断 */
	WWDG_EnableIT();

    /* 设置 WWDG 的NVIC */
	NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);	
}


/*
*********************************************************************************************************
*	函 数 名: WWDG_IRQHandler
*	功能说明: 窗口看门狗调用中断服务程序。
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void WWDG_IRQHandler(void)
{
	/*特别注意，下面两句的执行顺序不能反了，反了就出问题了*/
	/* 清除EWI标志 */
	if (WWDG_GetFlagStatus != RESET)
	{
		/* 清除复位标志 */
		WWDG_ClearFlag();
		
		/* 更新窗口看门狗计数器 */
		WWDG_SetCounter(127);
	}	
}

/***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/
